package xxl.signals.impl 
{
	import xxl.signals.api.events.IBubbleEventHandler;
	import xxl.signals.api.events.IEvent;
	import xxl.signals.api.IDeluxeSignal;
	import xxl.signals.impl.events.GenericEvent;
	import xxl.signals.util.ReflectorUtil;
	import xxl.signals.util.SignalUtil;
	/**
	 * ...
	 * @author XXL
	 */
	public class DeluxeSignal extends PrioritySignal implements IDeluxeSignal
	{
		protected const reflectorUtil:ReflectorUtil = ReflectorUtil.GetInstance();
		protected var _target:Object;
		
		public function DeluxeSignal(target:Object = null, ...valueClasses) 
		{
			_target = target;
			
			valueClasses = (valueClasses.length == 1 && valueClasses[0] is Array) ? valueClasses[0]:valueClasses;
			super(valueClasses);
		}
		
		public function get target():Object
		{
			return _target;
		}
		public function set target(value:Object):void
		{
			if (value == _target)
			{
				return ;
			}
			removeAll();
			_target = value;
		}
		
		override public function set valueClasses(value:Array):void 
		{
			SignalUtil.VerifyValueClasses(value);
			if (value && value.length > 0)
			{
				if (reflectorUtil.typeImplements(IEvent, value[0]))
				{
					_valueClasses = value;
					return;
				}
			}
			_valueClasses = value ? [IEvent].concat(value) : [IEvent];
		}
		
		override public function dispatch(...valueObjects):void 
		{
			var currentTarget:Object = target;
			var event:IEvent = valueObjects[0] as IEvent;
			
			if (!event)
			{
				event = new GenericEvent();
				valueObjects = [event].concat(valueObjects);
			}
			SignalUtil.VerifyDispatch(valueClasses, valueObjects);
			
			if (event.target)
			{
				event = event.clone();
				valueObjects[0] = event;
			}
			event.target = currentTarget;
			event.currentTarget = currentTarget;
			event.signal = this;
			
			if (sortFlag)
			{
				sortFlag = false;
				slots = slots.sortOn("priority", Array.NUMERIC | Array.DESCENDING);
			}
			
			for (var i:int = slots.length; i--; )
			{
				slots[i].execute(valueObjects);
			}
			
			if (event && event.bubbles)
			{
				while (currentTarget && ("parent" in currentTarget))
				{
					currentTarget = currentTarget["parent"];
					if (currentTarget is IBubbleEventHandler)
					{
						if (!IBubbleEventHandler(event.currentTarget = currentTarget).onEventBubbled(event))
						{
							break;
						}
					}
				}
			}
		}
	}

}